package org.goodsl.mdd;

import groovy.lang.Closure;

import java.util.HashMap;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: Simon Xiao
 * Date: 13-1-18
 * Time: 上午9:03
 * Copyright goodsl.org 2012~2020
 */
public class DependParseDelegate {
    public String dependAspectName;
    public HashMap<String, SegInBox> ps;
    public SegInBox dependBySeg;
    public Box theBox;

    public DependParseDelegate(Box instance, String depName, HashMap<String, SegInBox> ps) {
        this.theBox = instance;
        dependAspectName = depName;
        this.ps = ps;
        dependBySeg = null;
    }

    public DependParseDelegate(Box instance, String depName, HashMap<String, SegInBox> ps, SegInBox dependBy) {
        this.theBox = instance;
        dependAspectName = depName;
        this.ps = ps;
        dependBySeg = dependBy;
    }

    public Object methodMissing(String boxSegName, Object args)throws ParseException{
        if (!ps.containsKey(boxSegName)) {
            throw new ParseException("类型 " +theBox.getClass().getName() + " 没有定义名为 " + boxSegName +" 的属性");
        }

        List argsList = (List)args;


        SegInBox segInBox = ps.get(boxSegName);
        if (dependBySeg != null)
            dependBySeg.dependOn(dependAspectName, segInBox, true);

        if (argsList != null && argsList.size() > 0 && argsList.get(0) instanceof Closure) {
            Closure cl = (Closure) argsList.get(0);
            DependParseDelegate newDelegate = new DependParseDelegate(theBox, dependAspectName, ps, segInBox);
            cl.setDelegate(newDelegate);
            cl.setResolveStrategy(Closure.DELEGATE_FIRST);
            Object theSeg = theBox.getSeg(boxSegName);

            //闭包执行体需要被保存起来，用于运行时计算值
            //每个 Box 的类型中，一个“属性名称+依赖项名称”映射一个闭包，用于运算时的求值
            if (dependBySeg == null) {//第一层
                //只对第一层的保留闭包代码，内层只用于计算
                segInBox.dependSegCode.put(dependAspectName,cl);

            }

            //将字段本身作为闭包的默认参数.递归执行，
            //这里是解析时间的执行，主要用于计算依赖关系
            //todo: 考虑是否不解析嵌套的依赖
            //if(dependBySeg==null)
            return cl.call(theSeg);


        }
        return  null;
    }
}
